/*
 * @Author: lujin49
 * @Date: 2025-01-07 11:20:47
 * @LastEditTime: 2025-01-07 12:07:16
 * @Description:
 */
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode/utf8"

	"golang.org/x/text/encoding/simplifiedchinese"
)

// 需要处理的文件扩展名
var validExtensions = map[string]bool{
	".txt":  true,
	".json": true,
	".go":   true,
	".java": true,
	".py":   true,
	".js":   true,
	".html": true,
	".css":  true,
	".xml":  true,
	".cpp":  true,
	".c":    true,
	".h":    true,
	".hpp":  true,
	".php":  true,
	".sql":  true,
	".yaml": true,
	".yml":  true,
	".md":   true,
}

// 检测文件是否为UTF-8编码
func isUTF8(content []byte) bool {
	return utf8.Valid(content)
}

// 检测文件是否可能是GB2312/GBK编码
func isGB2312(content []byte) bool {
	// 尝试将内容从GB18030转换为UTF-8
	decoder := simplifiedchinese.GB18030.NewDecoder()
	_, err := decoder.Bytes(content)
	if err != nil {
		return false
	}

	// 检查是否包含中文字符
	hasChineseChars := false
	for i := 0; i < len(content)-1; i++ {
		if content[i] >= 0x81 && content[i] <= 0xFE &&
			content[i+1] >= 0x40 && content[i+1] <= 0xFE {
			hasChineseChars = true
			break
		}
	}

	return hasChineseChars
}

// 转换单个文件的编码
func convertFileEncoding(filePath string) error {
	// 读取文件内容
	content, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("读取文件时发生错误: %v", err)
	}

	// 检查文件编码
	if isUTF8(content) {
		fmt.Printf("文件 '%s' 已经是 UTF-8 编码，跳过转换\n", filepath.Base(filePath))
		return nil
	}

	if !isGB2312(content) {
		fmt.Printf("文件 '%s' 可能不是 GB2312/GBK 编码，跳过转换\n", filepath.Base(filePath))
		return nil
	}

	// 创建GB2312解码器
	decoder := simplifiedchinese.GB18030.NewDecoder()

	// 转换编码
	utf8Content, err := decoder.Bytes(content)
	if err != nil {
		return fmt.Errorf("转换编码时发生错误: %v", err)
	}

	// 删除源文件
	if err := os.Remove(filePath); err != nil {
		return fmt.Errorf("删除源文件时发生错误: %v", err)
	}

	// 将转换后的内容写回文件
	if err = os.WriteFile(filePath, utf8Content, 0644); err != nil {
		return fmt.Errorf("写入文件时发生错误: %v", err)
	}

	fmt.Printf("文件 '%s' 已成功转换为 UTF-8 编码\n", filepath.Base(filePath))
	return nil
}

// 处理文件夹
func processDirectory(dirPath string) error {
	return filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录
		if info.IsDir() {
			return nil
		}

		// 检查文件扩展名
		ext := strings.ToLower(filepath.Ext(path))
		if validExtensions[ext] {
			if err := convertFileEncoding(path); err != nil {
				fmt.Printf("处理文件 '%s' 时发生错误: %v\n", path, err)
			}
		}

		return nil
	})
}

func main() {
	// 检查命令行参数
	if len(os.Args) != 2 {
		fmt.Println("使用方法: go run main.go <文件路径或目录路径>")
		os.Exit(1)
	}

	inputPath := os.Args[1]

	// 检查路径是否存在
	fileInfo, err := os.Stat(inputPath)
	if os.IsNotExist(err) {
		fmt.Printf("错误: 路径 '%s' 不存在\n", inputPath)
		os.Exit(1)
	}

	// 根据路径类型进行处理
	if fileInfo.IsDir() {
		// 处理目录
		if err := processDirectory(inputPath); err != nil {
			fmt.Printf("处理目录时发生错误: %v\n", err)
			os.Exit(1)
		}
		fmt.Println("目录处理完成")
	} else {
		// 处理单个文件
		ext := strings.ToLower(filepath.Ext(inputPath))
		if !validExtensions[ext] {
			fmt.Printf("错误: 不支持的文件类型 '%s'\n", ext)
			os.Exit(1)
		}

		if err := convertFileEncoding(inputPath); err != nil {
			fmt.Printf("错误: %v\n", err)
			os.Exit(1)
		}
	}
}
